Imports System.Drawing
Imports System.Windows.Forms
Imports Vintasoft.Imaging
Imports Vintasoft.Pdf
Imports Vintasoft.Pdf.Tree
Imports System.ComponentModel

Namespace Pdf
	Public Class BookmarkTreeView
		Inherits TreeView

		#Region "Fields"

		Private bookmarksMenuStrip As ContextMenuStrip
		Private components As IContainer
		Private addToolStripMenuItem As ToolStripMenuItem
		Private editToolStripMenuItem As ToolStripMenuItem
		Private deleteOutlineNodeToolStripMenuItem As ToolStripMenuItem
		Private moveUpToolStripMenuItem As ToolStripMenuItem
		Private moveDownToolStripMenuItem As ToolStripMenuItem

		#End Region



		#Region "Constructor"

		Public Sub New()
			InitializeComponent()
		End Sub

		#End Region



		#Region "Properties"

		Private _document As PdfDocument
		Public Property Document() As PdfDocument
			Get
				Return _document
			End Get
			Set
				If _document IsNot value Then
					_document = value
					ShowBookmarks()
				End If
			End Set
		End Property

		Private _viewer As ImageViewerBase
		Public Property Viewer() As ImageViewerBase
			Get
				Return _viewer
			End Get
			Set
				_viewer = value
			End Set
		End Property

		Private _canEditBookmarks As Boolean = False
		<DefaultValue(False)> _
		Public Property CanEditBookmarks() As Boolean
			Get
				Return _canEditBookmarks
			End Get
			Set
				_canEditBookmarks = value
				If _canEditBookmarks Then
					ContextMenuStrip = bookmarksMenuStrip
				Else
					ContextMenuStrip = Nothing
				End If
			End Set
		End Property

		#End Region



		#Region "Designer"

		Private Sub InitializeComponent()
			Me.components = New System.ComponentModel.Container()
			Me.bookmarksMenuStrip = New System.Windows.Forms.ContextMenuStrip(Me.components)
			Me.addToolStripMenuItem = New System.Windows.Forms.ToolStripMenuItem()
			Me.editToolStripMenuItem = New System.Windows.Forms.ToolStripMenuItem()
			Me.deleteOutlineNodeToolStripMenuItem = New System.Windows.Forms.ToolStripMenuItem()
			Me.moveUpToolStripMenuItem = New System.Windows.Forms.ToolStripMenuItem()
			Me.moveDownToolStripMenuItem = New System.Windows.Forms.ToolStripMenuItem()
			Me.bookmarksMenuStrip.SuspendLayout()
			Me.SuspendLayout()
			' 
			' bookmarksMenuStrip
			' 
			Me.bookmarksMenuStrip.Items.AddRange(New System.Windows.Forms.ToolStripItem() {Me.addToolStripMenuItem, Me.editToolStripMenuItem, Me.deleteOutlineNodeToolStripMenuItem, Me.moveUpToolStripMenuItem, Me.moveDownToolStripMenuItem})
			Me.bookmarksMenuStrip.Name = "outlineMenuStrip"
			Me.bookmarksMenuStrip.Size = New System.Drawing.Size(204, 114)
			AddHandler Me.bookmarksMenuStrip.Opening, New CancelEventHandler(AddressOf bookmarksMenuStrip_Opening)
			' 
			' addToolStripMenuItem
			' 
			Me.addToolStripMenuItem.Name = "addToolStripMenuItem"
			Me.addToolStripMenuItem.Size = New System.Drawing.Size(203, 22)
			Me.addToolStripMenuItem.Text = "Add..."
			AddHandler Me.addToolStripMenuItem.Click, New System.EventHandler(AddressOf addBookmarkToolStripMenuItem_Click)
			' 
			' editToolStripMenuItem
			' 
			Me.editToolStripMenuItem.Name = "editToolStripMenuItem"
			Me.editToolStripMenuItem.Size = New System.Drawing.Size(203, 22)
			Me.editToolStripMenuItem.Text = "Edit..."
			AddHandler Me.editToolStripMenuItem.Click, New EventHandler(AddressOf editToolStripMenuItem_Click)
			' 
			' deleteOutlineNodeToolStripMenuItem
			' 
			Me.deleteOutlineNodeToolStripMenuItem.Name = "deleteOutlineNodeToolStripMenuItem"
			Me.deleteOutlineNodeToolStripMenuItem.Size = New System.Drawing.Size(203, 22)
			Me.deleteOutlineNodeToolStripMenuItem.Text = "Delete"
			AddHandler Me.deleteOutlineNodeToolStripMenuItem.Click, New System.EventHandler(AddressOf deleteBookmarkNodeToolStripMenuItem_Click)
			' 
			' moveUpToolStripMenuItem
			' 
			Me.moveUpToolStripMenuItem.Name = "moveUpToolStripMenuItem"
			Me.moveUpToolStripMenuItem.ShortcutKeys = CType((System.Windows.Forms.Keys.Control Or System.Windows.Forms.Keys.Up), System.Windows.Forms.Keys)
			Me.moveUpToolStripMenuItem.Size = New System.Drawing.Size(203, 22)
			Me.moveUpToolStripMenuItem.Text = "Move Up"
			AddHandler Me.moveUpToolStripMenuItem.Click, New EventHandler(AddressOf moveUpBookmarkToolStripMenuItem_Click)
			' 
			' moveDownToolStripMenuItem
			' 
			Me.moveDownToolStripMenuItem.Name = "moveDownToolStripMenuItem"
			Me.moveDownToolStripMenuItem.ShortcutKeys = CType((System.Windows.Forms.Keys.Control Or System.Windows.Forms.Keys.Down), System.Windows.Forms.Keys)
			Me.moveDownToolStripMenuItem.Size = New System.Drawing.Size(203, 22)
			Me.moveDownToolStripMenuItem.Text = "Move Down"
			AddHandler Me.moveDownToolStripMenuItem.Click, New EventHandler(AddressOf moveDownBookmarkToolStripMenuItem_Click)
			' 
			' BookmarkTreeView
			' 
			Me.LineColor = System.Drawing.Color.Black
			Me.bookmarksMenuStrip.ResumeLayout(False)
			Me.ResumeLayout(False)

		End Sub

		#End Region



		#Region "Methods"


		' Show bookmarks.
		Public Sub ShowBookmarks()
			Nodes.Clear()
			If _document IsNot Nothing Then
				SyncLock _document
					AddBookmarks(Nodes, _document.Bookmarks)
				End SyncLock
			End If
		End Sub

		Public Sub AddBookmark(pageIndex As Integer)
			Dim outline As New PdfBookmark(_document)
			Dim dialog As New EditBookmarkNodeForm(_viewer, pageIndex, outline, True)
			If dialog.ShowDialog() = System.Windows.Forms.DialogResult.OK Then
				Dim bookmarks As PdfBookmarkCollection = Nothing
				Dim nodes__1 As TreeNodeCollection = Nothing
				If SelectedNode IsNot Nothing AndAlso Not dialog.AddToRoot Then
					bookmarks = DirectCast(SelectedNode.Tag, PdfBookmark).ChildBookmarks
					nodes__1 = SelectedNode.Nodes
				Else
					If _document.Bookmarks Is Nothing Then
						_document.Bookmarks = New PdfBookmarkCollection(_document)
					End If
					bookmarks = _document.Bookmarks
					nodes__1 = Nodes
				End If

				bookmarks.Add(dialog.Bookmark)
				SelectedNode = AddBookmark(nodes__1, outline)

				_document.DocumentViewMode = PdfDocumentViewMode.UseOutlines
			End If
		End Sub

		Public Sub DeleteSelectedBookmark()
			If CanEditBookmarks Then
				If SelectedNode IsNot Nothing Then
					Dim current As PdfBookmark = DirectCast(SelectedNode.Tag, PdfBookmark)
					current.Remove()
					SelectedNode.Remove()
				End If
			End If
		End Sub

		Public Sub EditSelectedBookmark()
			If CanEditBookmarks Then
				If SelectedNode IsNot Nothing Then
					Dim outline As PdfBookmark = DirectCast(SelectedNode.Tag, PdfBookmark)

					Dim pageIndex As Integer = 0
					If _viewer IsNot Nothing AndAlso _viewer.FocusedIndex >= 0 Then
						pageIndex = _viewer.FocusedIndex
					End If
					If outline.Destination IsNot Nothing Then
						pageIndex = _document.Pages.IndexOf(outline.Destination.Page)
					End If

					Dim dialog As New EditBookmarkNodeForm(_viewer, pageIndex, outline, False)
					If dialog.ShowDialog() = System.Windows.Forms.DialogResult.OK Then
						Dim treeNodes As TreeNodeCollection
						If SelectedNode.Parent IsNot Nothing Then
							treeNodes = SelectedNode.Parent.Nodes
						Else
							treeNodes = Nodes
						End If

						Dim index As Integer = treeNodes.IndexOf(SelectedNode)
						SelectedNode.Remove()
						treeNodes.Insert(index, AddBookmark(Nothing, dialog.Bookmark))
						SelectedNode = treeNodes(index)
					End If
				End If
			End If
		End Sub

		' Add bookmarks to specified tree node collection.
		Private Sub AddBookmarks([to] As TreeNodeCollection, from As PdfBookmarkCollection)
			If from IsNot Nothing Then
				Dim count As Integer = from.Count
				For i As Integer = 0 To count - 1
					AddBookmark([to], from(i))
				Next
			End If
		End Sub

		' Add bookmark to specified tree node collection.
		Public Function AddBookmark([to] As TreeNodeCollection, item As PdfBookmark) As TreeNode
			Dim node As New TreeNode(item.Title)
			node.Tag = item
			If [to] IsNot Nothing Then
				[to].Add(node)
			End If
			node.NodeFont = Font
			If item.Flags <> PdfBookmarkFlags.None Then
				Dim style As FontStyle = FontStyle.Regular
				If (item.Flags And PdfBookmarkFlags.Bold) <> 0 Then
					style = style Or FontStyle.Bold
				End If
				If (item.Flags And PdfBookmarkFlags.Italic) <> 0 Then
					style = style Or FontStyle.Italic
				End If
				node.NodeFont = New Font(node.NodeFont, style)
			End If
			If item.ChildBookmarks IsNot Nothing Then
				AddBookmarks(node.Nodes, item.ChildBookmarks)
			End If
			node.ForeColor = item.Color
			'if (item.IsExpanded)
			'node.Expand();
			Return node
		End Function

		' Set current page index to bookmark destination page index.
		Protected Overrides Sub OnAfterSelect(e As TreeViewEventArgs)
			MyBase.OnAfterSelect(e)

			If _viewer IsNot Nothing Then
				If _document Is Nothing Then
					Return
				End If
				Dim pageIndexInCollection As Integer = FindPageIndexInViewer(DirectCast(SelectedNode.Tag, PdfBookmark))
				If pageIndexInCollection < 0 Then
					DemosTools.ShowWarningMessage("Bookmarks", "Destination page of this bookmark was not found.")
				Else
					_viewer.FocusedIndex = pageIndexInCollection
				End If
			End If
		End Sub

		' Search bookmark destination page in the viewer image collection.
		Private Function FindPageIndexInViewer(bookmark As PdfBookmark) As Integer
			Dim pageIndexInCollection As Integer = -1
			SyncLock _document
				Dim dest As PdfDestinationBase = bookmark.Destination
				If dest IsNot Nothing Then
					Dim pageIndexInDocument As Integer = _document.Pages.IndexOf(dest.Page)
					Return FindDocumentPageIndexInImageCollection(_document, pageIndexInDocument, _viewer.Images)
				End If
			End SyncLock
			Return pageIndexInCollection
		End Function


		' Move bookmark at delta positions.
		Private Sub MoveBookmark(node As TreeNode, delta As Integer)
			Dim parentNodes As TreeNodeCollection
			If node.Parent IsNot Nothing Then
				parentNodes = node.Parent.Nodes
			Else
				parentNodes = node.TreeView.Nodes
			End If
			Dim outline As PdfBookmark = DirectCast(node.Tag, PdfBookmark)
			Dim parentOutlines As PdfBookmarkCollection = outline.ParentBookmarks

			Dim currentIndex As Integer = parentOutlines.IndexOf(outline)
			Dim newIndex As Integer = currentIndex + delta
			If newIndex < 0 Then
				newIndex = 0
			End If
			If newIndex >= parentOutlines.Count Then
				newIndex = parentOutlines.Count - 1
			End If
			If newIndex = currentIndex Then
				Return
			End If

			parentOutlines.RemoveAt(currentIndex)
			parentOutlines.Insert(newIndex, outline)

			node.TreeView.SelectedNode = Nothing

			parentNodes.RemoveAt(currentIndex)
			parentNodes.Insert(newIndex, node)

			node.TreeView.SelectedNode = node
		End Sub

		' Search PDF page index in the image collection.
		Private Shared Function FindDocumentPageIndexInImageCollection(document As PdfDocument, pageIndexInDocument As Integer, images As ImageCollection) As Integer
			Dim pageIndexInCollection As Integer = -1
			If pageIndexInDocument >= 0 Then
				Dim info As ImageSourceInfo
				If pageIndexInDocument < images.Count Then
					info = images(pageIndexInDocument).SourceInfo
					If info.Stream Is document.SourceStream Then
						If info.PageIndex = pageIndexInDocument Then
							pageIndexInCollection = pageIndexInDocument
						End If
					End If
				End If
				If pageIndexInCollection < 0 Then
					For i As Integer = 0 To images.Count - 1
						info = images(i).SourceInfo
						If info.Stream Is document.SourceStream Then
							If info.PageIndex = pageIndexInDocument Then
								pageIndexInCollection = i
								Exit For
							End If
						End If
					Next
				End If
			End If
			Return pageIndexInCollection
		End Function


		' Add new bookmark.
		Private Sub addBookmarkToolStripMenuItem_Click(sender As Object, e As EventArgs)
			Dim pageIndex As Integer = 0
			If _viewer IsNot Nothing AndAlso _viewer.FocusedIndex >= 0 Then
				pageIndex = _viewer.FocusedIndex
			End If
			AddBookmark(pageIndex)
		End Sub

		' Delete bookmark.
		Private Sub deleteBookmarkNodeToolStripMenuItem_Click(sender As Object, e As EventArgs)
			DeleteSelectedBookmark()
		End Sub

		' Edit selected bookmark.
		Protected Overrides Sub OnDoubleClick(e As EventArgs)
			MyBase.OnDoubleClick(e)

			EditSelectedBookmark()
		End Sub


		Private Sub editToolStripMenuItem_Click(sender As Object, e As EventArgs)
			EditSelectedBookmark()
		End Sub

		' Moves down selected bookmark.
		Private Sub moveDownBookmarkToolStripMenuItem_Click(sender As Object, e As EventArgs)
			If SelectedNode IsNot Nothing Then
				MoveBookmark(SelectedNode, 1)
			End If
		End Sub

		' Moves up selected bookmark.
		Private Sub moveUpBookmarkToolStripMenuItem_Click(sender As Object, e As EventArgs)
			If SelectedNode IsNot Nothing Then
				MoveBookmark(SelectedNode, -1)
			End If
		End Sub

		Protected Overrides Sub OnNodeMouseClick(e As TreeNodeMouseClickEventArgs)
			MyBase.OnNodeMouseClick(e)

			If e.Button = MouseButtons.Right Then
				SelectedNode = e.Node
			End If
		End Sub

		Private Sub bookmarksMenuStrip_Opening(sender As Object, e As CancelEventArgs)
			If Not CanEditBookmarks OrElse _document Is Nothing Then
				e.Cancel = True
			Else
				Dim canEdit As Boolean = SelectedNode IsNot Nothing
				moveDownToolStripMenuItem.Enabled = canEdit
				moveUpToolStripMenuItem.Enabled = canEdit
				editToolStripMenuItem.Enabled = canEdit
				deleteOutlineNodeToolStripMenuItem.Enabled = canEdit
			End If
		End Sub

		#End Region

	End Class
End Namespace
